package service

import (
	"ia/apps/admin/web/dts/sin"
	"ia/common/icasbin"
	"ia/common/model/modeladmin"
	"ia/common/storage"
	"ia/common/support"
	"ia/common/support/define"
	"strconv"

	"github.com/kataras/golog"
	"github.com/kataras/iris/v12"
	"gorm.io/gorm"
)

type AdminRoleService interface {
	Create(ctx iris.Context)
	Delete(ctx iris.Context)
	Update(ctx iris.Context)
	Table(ctx iris.Context)
	List(ctx iris.Context)
	Grant(ctx iris.Context)
	Owned(ctx iris.Context)
}

func NewAdminRoleService() *adminRoleService {
	return &adminRoleService{}
}

type adminRoleService struct{}

func (impl *adminRoleService) Create(ctx iris.Context) {
	var (
		code define.Code
		err  error
		in   modeladmin.AdminRole
	)
	if err = ctx.ReadJSON(&in); err != nil {
		goto ERR
	}
	if err = storage.GDB1.Create(&in).Error; err != nil {
		goto ERR
	}
	support.Ok_(ctx)
	return
ERR:
	golog.Errorf("错误：%s", err)
	support.InternalServerError(ctx, code)
}

func (impl *adminRoleService) Delete(ctx iris.Context) {
	var (
		code   define.Code
		err    error
		idList = make([]int, 0)
	)
	if err = ctx.ReadJSON(&idList); err != nil {
		goto ERR
	}

	if err = storage.GDB1.Transaction(func(tx *gorm.DB) error {
		if err = tx.Delete(&modeladmin.AdminRole{}, "id in ?", idList).Error; err != nil {
			return err
		}
		if err = tx.Delete(&modeladmin.AdminRoleMenu{}, "rid in ?", idList).Error; err != nil {
			return err
		}
		if err = tx.Delete(&modeladmin.AdminRolePolicy{}, "rid in ?", idList).Error; err != nil {
			return err
		}
		if err = tx.Delete(&modeladmin.CasbinRule{},
			"(ptype='g' AND v1 in ?) OR (ptype='p' AND v0 in ?)", idList, idList).Error; err != nil {
			return err
		}
		return nil
	}); err != nil {
		goto ERR
	}
	support.OkTip(ctx, nil)
	return
ERR:
	golog.Errorf("错误：%s", err)
	support.InternalServerError(ctx, code)
}

func (impl *adminRoleService) Update(ctx iris.Context) {
	var (
		code define.Code
		err  error
		in   modeladmin.AdminRole
	)
	if err = ctx.ReadJSON(&in); err != nil {
		goto ERR
	}

	if err = storage.GDB1.Save(&in).Error; err != nil {
		goto ERR
	}
	support.Ok_(ctx)
	return
ERR:
	golog.Errorf("错误：%s", err)
	support.InternalServerError(ctx, code)
}

func (impl *adminRoleService) Table(ctx iris.Context) {
	var (
		code   define.Code
		err    error
		in     sin.VxeTableIn
		total  int64
		result = make([]*modeladmin.AdminRole, 0)
	)
	if err = ctx.ReadQuery(&in); err != nil {
		goto ERR
	}
	if err = storage.GDB1.Model(&modeladmin.AdminRole{}).Count(&total).Error; err != nil {
		goto ERR
	}
	if err = storage.GDB1.
		Offset(in.Offset()).Limit(in.PageSize).
		Find(&result).Error; err != nil {
		goto ERR
	}
	support.VxeTableData(ctx, in.PageSize, in.CurrentPage, total, result, nil)
	return
ERR:
	golog.Errorf("错误：%s", err)
	support.InternalServerError(ctx, code)
}

func (impl *adminRoleService) List(ctx iris.Context) {
	var (
		code   define.Code
		err    error
		result = make([]*modeladmin.AdminRole, 0)
	)
	if err = storage.GDB1.Find(&result).Error; err != nil {
		goto ERR
	}
	support.Ok(ctx, result)
	return
ERR:
	golog.Errorf("错误：%s", err)
	support.InternalServerError(ctx, code)
}

func (impl *adminRoleService) Grant(ctx iris.Context) {
	var (
		code       define.Code
		err        error
		in         sin.AdminRoleGrant
		policyList = make([]*modeladmin.AdminPolicy, 0)
		m1         = make([]*modeladmin.CasbinRule, 0)
		m2         = make([]*modeladmin.AdminRoleMenu, 0)
	)
	if err = ctx.ReadJSON(&in); err != nil {
		goto ERR
	}

	if err = storage.GDB1.Find(&policyList, "id in ?", in.PidList).Error; err != nil {
		goto ERR
	}
	if err = storage.GDB1.Transaction(func(tx *gorm.DB) error {
		if err = tx.Delete(&modeladmin.CasbinRule{}, "ptype='p' AND v0 = ?", in.Rid).Error; err != nil {
			return err
		}
		if err = tx.Delete(&modeladmin.AdminRolePolicy{}, "rid = ?", in.Rid).Error; err != nil {
			return err
		}
		if err = tx.Delete(&modeladmin.AdminRoleMenu{}, "rid = ?", in.Rid).Error; err != nil {
			return err
		}
		//
		if in.Rid > 0 && len(policyList) > 0 {
			for _, v := range policyList {
				m1 = append(m1, &modeladmin.CasbinRule{
					Ptype: "p",
					V0:    strconv.Itoa(in.Rid),
					V1:    v.V1,
					V2:    v.V2,
					V3:    v.V3,
					V4:    v.V4,
					V5:    v.V5,
				})
			}
		}
		if err = tx.CreateInBatches(m1, 100).Error; err != nil {
			return err
		}
		for _, v := range in.PidList {
			if err = tx.Create(&modeladmin.AdminRolePolicy{
				Rid: uint(in.Rid),
				Pid: uint(v),
			}).Error; err != nil {
				return err
			}
		}

		if in.Rid > 0 && len(in.MidList) > 0 {
			for _, v := range in.MidList {
				if len(v.Bid) > 0 {
					for _, vv := range v.Bid {
						m2 = append(m2, &modeladmin.AdminRoleMenu{
							Rid: uint(in.Rid),
							Mid: uint(v.Id),
							Bid: uint(vv),
						})
					}
				} else {
					m2 = append(m2, &modeladmin.AdminRoleMenu{
						Rid: uint(in.Rid),
						Mid: uint(v.Id),
					})
				}
			}
		}
		if err = tx.CreateInBatches(m2, 100).Error; err != nil {
			return err
		}
		return nil
	}); err != nil {
		goto ERR
	}
	if err = icasbin.GCasbin.LoadPolicy(); err != nil {
		goto ERR
	}
	support.OkTip(ctx, nil)
	return
ERR:
	golog.Errorf("错误：%s", err)
	support.InternalServerError(ctx, code)
}

func (impl *adminRoleService) Owned(ctx iris.Context) {
	var (
		code       define.Code
		err        error
		rid        = ctx.URLParamIntDefault("rid", 0)
		menuList   = make([]int64, 0)
		policyList = make([]int64, 0)
	)
	if err = storage.GDB1.Model(&modeladmin.AdminRoleMenu{}).Select("distinct mid").
		Where("rid=?", rid).
		Scan(&menuList).Error; err != nil {
		goto ERR
	}
	if err = storage.GDB1.Model(&modeladmin.AdminRolePolicy{}).Select("distinct pid").
		Where("rid=?", rid).
		Scan(&policyList).Error; err != nil {
		goto ERR
	}
	support.Ok(ctx, iris.Map{
		"menuList":   menuList,
		"policyList": policyList,
	})
	return
ERR:
	golog.Errorf("错误：%s", err)
	support.InternalServerError(ctx, code)
}
